package nl.rug.jvleusen.datastructurelib;

import java.util.List;
import nl.rug.jvleusen.datastructurelib.graph.UnweightedDirectionalGraph;
import nl.rug.jvleusen.datastructurelib.graph.UnweightedUndirectionalGraph;
import nl.rug.jvleusen.datastructurelib.graph.WeightedDirectionalGraph;
import nl.rug.jvleusen.datastructurelib.graph.WeightedUndirectionalGraph;

/**
 * This is the interface for each class implementing a graph in this library,
 * any implementation should follow the definition of the {@link Iterable}
 * interface. Weighted graph implementations should extend {@link AbstractWeightedGraph}
 * to allow usage of edge-related methods and related algorithms.
 *
 * Note that in any implementation of this interface, methods where you specify
 * two vertices do care about the order they are specified in, when a graph is
 * directional it will only check x -> y, while undirectional graphs will also
 * check y -> x
 *
 * @author Jeroen van Leusen
 * @see AbstractWeightedGraph
 * @see WeightedDirectionalGraph
 * @see WeightedUndirectionalGraph
 * @see UnweightedDirectionalGraph
 * @see UnweightedUndirectionalGraph
 */
public interface IGraph<E> extends Iterable<E> {

    /**
     * This method evaluates whether there is an edge between the the two
     * vertices specified by the input if there is it will return true, is there
     * no edge, or is does one/both of the vertices not exist, return false too.
     *
     * @param x First item that might exist in the graph.
     * @param y Second item that might exist in the graph.
     * @return Whether there is an edge between the vertex holding x and the
     * vertex holding y, will return false if there is no such edge or if either
     * vertex can be found.
     */
    public boolean adjacent(E x, E y);

    /**
     * Gets a list of all vertices which have an edge from the specified node,
     * it should return an empty list if the node has no neighbors), and will
     * return null if the node in question is not part of the graph.
     *
     * @param x The node in question.
     * @return A list of all nodes adjacent to the specified node, will return
     * an empty list if the node has no adjacent nodes and will return NULL if
     * the node doesn't exist.
     */
    public List<E> neighbors(E x);

    /**
     * Adds an edge from the first item to the second, if it doesn't already
     * exist, if either vertices is not part of the graph yet, add it.
     *
     * @param x The first item
     * @param y The second item
     * @return Whether this graph changed as a result of this action, this
     * signifies if you actually added an edge or if it already existed
     * beforehand.
     */
    public boolean add(E x, E y);

    /**
     * Deletes the edge between the first item and the second item, should one
     * of the vertices run out of edges from this action it should be removed
     * from the graph, but this is up to the implementation to decide on,
     * returns false if there is no edge.
     *
     * @param x The first item
     * @param y The second item
     * @return Whether this graph changed as a result of this action, this
     * signifies if you actually removed an edge or if there was no edge to
     * remove.
     */
    public boolean delete(E x, E y);

    /**
     * Returns whether a vertice with the specified item in it exists within the
     * graph
     *
     * @param x Item to look for
     * @return Whether said vertex exists.
     */
    public boolean contains(E x);
}
